package bueu.bexl;

import java.util.List;

import bueu.bexl.utils.Property;

import static bueu.bexl.utils.TypeUtils.numberValue;

public class PropertyExpr extends ReferenceExpr {

	private final String name;
	private final BexlExpr index;
	private final BexlExpr realNext;

	public PropertyExpr(final String name, final boolean ofContext, final BexlExpr next) {
		super(next, ofContext);
		this.name = name;
		
		if (next instanceof FilterExpr && !((FilterExpr) next).getExpr().isRelative()) {
			FilterExpr filter = (FilterExpr) next;
			this.index = filter.getExpr();
			this.realNext = filter.getNext(); 
		} else {
			this.index = null;
			this.realNext = next;
		}
	}

	@Override
	public final String toString() {
		final StringBuilder sb = new StringBuilder();

		if (this.ofContext) {
			sb.append("$");
		}

		sb.append(this.name);
		toStringNext(sb);
		
		return sb.toString();
	}

	protected final void eval(final BexlCtx ctx, final Object current, final boolean set,
			final Object newValue, final List<Object> result) throws BexlException {
		final Property property = Property.get(current.getClass(), this.name);
		
		if (property == null) {
			return;
		}
		
		Integer index = null;

		if (this.index != null) {
			index = new Double(numberValue(this.index.eval(ctx, current, false, null))).intValue();
		}

		if (set && this.realNext == null) {
			property.set(current, index, newValue);
		} else {
			final Object value = property.get(current, index == null && set? new Integer(0) : index, set);
			
			if (value != null) {
				if (isArray(value)) {
					final Object[] array = toArray(value);
					final int length = array.length;
	
					for (int i = 0; i < length; i++) {
						processNext(this.realNext, ctx, array[i], set, newValue, result);
					}
				} else {
					processNext(this.realNext, ctx, value, set, newValue, result);
				}
			}
		}
	}
}
